#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<arpa/inet.h>   //字节序转换接口
#include<netinet/in.h>  //地质结构类型与协议类型宏头文件
#include<sys/socket.h>  //套接字接口

int main(int argc,char* argv[])
{
  if(argc!=3){
    //若运行参数不是三个
    printf("./srv_udp 192.168.26.128 9000\n");
    return -1;
  }

  uint16_t port=atoi(argv[2]);    //获取第二个参数--转换为整数 atoi
  char* ip=argv[1];    //获取IP地址--第一个参数

  //1：创建套接字
  int sockfd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);      //采用 ipv4 类型地址域，udp数据报传输
  if(sockfd<0){
     perror("socket error!\n");
     return -1;
  }

  //2：为套接字绑定地址
  //首先创建一个地址信息
  struct sockaddr_in addr;        //定义 ipv4 类型地址结构
  addr.sin_family=AF_INET;   //地址域类型为 ipv4
  addr.sin_port=htons(port);    //端口号为 16 位的，因此使用 htons
  addr.sin_addr.s_addr=inet_addr(ip); //将获取到的点分十进制 IP 地址转换为整数类型的 
  socklen_t len=sizeof(struct sockaddr_in);

  int ret=bind(sockfd,(struct sockaddr*)&addr,len);    //绑定指定的地址信息
  if(ret==-1){
    perror("bind error!\n");
    return -1;
  }

  //3：循环收发数据
  while(1){
    char buf[1024]={0};
    struct sockaddr_in peer ;  //用来保存数据从哪里来--发送方地址
    socklen_t len=sizeof(struct sockaddr_in);
     
    //接收数据
    ssize_t ret=recvfrom(sockfd,buf,1023,0,(struct sockaddr*)&peer,&len);
    if(ret<0){
      perror("recvfrom error!\n");
      return -1;
    }
   char* peerip=inet_ntoa(peer.sin_addr); //获取点分十进制类型的IP地址
   uint16_t peerport=ntohs(peer.sin_port);    //网络类型端口转换为主机端口
   printf("client[%s:%d]say:%s\n ",peerip,peerport,buf);

   //发送数据
   char data[1024]={0};
   printf("serve say: ");
   fflush(stdout);
   scanf("%s",data); 
   ret=sendto(sockfd,data,strlen(data),0,(struct sockaddr*)&peer,len);
   if(ret<0){
     perror("sendto error!\n");
     return -1;
   }
  }
  //关闭套接字
  close(sockfd);
  return 0;
}
